"""
文件处理工具
处理文件上传、保存、验证等操作
"""

import os
import shutil
import hashlib
from pathlib import Path
from typing import Optional, Dict, Any
from datetime import datetime
import streamlit as st

from config import Config

class FileHandler:
    """文件处理器类"""
    
    def __init__(self):
        """初始化文件处理器"""
        self.config = Config()
    
    def save_uploaded_file(self, uploaded_file) -> str:
        """
        保存上传的文件
        
        Args:
            uploaded_file: Streamlit上传的文件对象
            
        Returns:
            保存的文件路径
        """
        # 验证文件
        self._validate_file(uploaded_file)
        
        # 生成安全的文件名
        safe_filename = self._generate_safe_filename(uploaded_file.name)
        
        # 构建保存路径
        file_path = self.config.UPLOAD_DIR / safe_filename
        
        # 保存文件
        with open(file_path, "wb") as f:
            f.write(uploaded_file.getbuffer())
        
        return str(file_path)
    
    def _validate_file(self, uploaded_file) -> None:
        """
        验证上传的文件
        
        Args:
            uploaded_file: 上传的文件对象
            
        Raises:
            ValueError: 文件验证失败
        """
        # 检查文件大小
        if uploaded_file.size > self.config.MAX_FILE_SIZE:
            raise ValueError(
                f"文件过大，最大允许 {self.config.MAX_FILE_SIZE / 1024 / 1024:.1f}MB"
            )
        
        # 检查文件扩展名
        file_extension = Path(uploaded_file.name).suffix.lower()
        if file_extension not in self.config.ALLOWED_EXTENSIONS:
            raise ValueError(
                f"不支持的文件格式 {file_extension}，"
                f"支持的格式: {', '.join(self.config.ALLOWED_EXTENSIONS)}"
            )
        
        # 检查文件内容（基本验证）
        if uploaded_file.size == 0:
            raise ValueError("文件为空")
    
    def _generate_safe_filename(self, original_filename: str) -> str:
        """
        生成安全的文件名
        
        Args:
            original_filename: 原始文件名
            
        Returns:
            安全的文件名
        """
        # 获取文件名和扩展名
        file_path = Path(original_filename)
        name = file_path.stem
        extension = file_path.suffix
        
        # 清理文件名（移除特殊字符）
        safe_name = "".join(c for c in name if c.isalnum() or c in (' ', '-', '_')).strip()
        
        # 如果清理后为空，使用默认名称
        if not safe_name:
            safe_name = "uploaded_file"
        
        # 添加时间戳避免冲突
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        
        # 生成最终文件名
        final_filename = f"{safe_name}_{timestamp}{extension}"
        
        return final_filename
    
    def get_file_info(self, file_path: str) -> Dict[str, Any]:
        """
        获取文件信息
        
        Args:
            file_path: 文件路径
            
        Returns:
            文件信息字典
        """
        file_path = Path(file_path)
        
        if not file_path.exists():
            raise FileNotFoundError(f"文件不存在: {file_path}")
        
        stat = file_path.stat()
        
        return {
            "filename": file_path.name,
            "size": stat.st_size,
            "size_mb": stat.st_size / 1024 / 1024,
            "created_time": datetime.fromtimestamp(stat.st_ctime),
            "modified_time": datetime.fromtimestamp(stat.st_mtime),
            "extension": file_path.suffix.lower(),
            "absolute_path": str(file_path.absolute())
        }
    
    def calculate_file_hash(self, file_path: str) -> str:
        """
        计算文件哈希值
        
        Args:
            file_path: 文件路径
            
        Returns:
            文件的MD5哈希值
        """
        hash_md5 = hashlib.md5()
        
        with open(file_path, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        
        return hash_md5.hexdigest()
    
    def cleanup_old_files(self, days: int = 7) -> int:
        """
        清理旧文件
        
        Args:
            days: 保留天数
            
        Returns:
            删除的文件数量
        """
        cutoff_time = datetime.now().timestamp() - (days * 24 * 3600)
        deleted_count = 0
        
        # 清理上传目录
        for file_path in self.config.UPLOAD_DIR.glob("*"):
            if file_path.is_file() and file_path.stat().st_mtime < cutoff_time:
                try:
                    file_path.unlink()
                    deleted_count += 1
                except Exception as e:
                    st.warning(f"删除文件失败 {file_path}: {e}")
        
        # 清理报告目录
        for file_path in self.config.REPORTS_DIR.glob("*"):
            if file_path.is_file() and file_path.stat().st_mtime < cutoff_time:
                try:
                    file_path.unlink()
                    deleted_count += 1
                except Exception as e:
                    st.warning(f"删除报告失败 {file_path}: {e}")
        
        return deleted_count
    
    def get_storage_usage(self) -> Dict[str, Any]:
        """
        获取存储使用情况
        
        Returns:
            存储使用信息
        """
        def get_dir_size(directory: Path) -> int:
            """计算目录大小"""
            total_size = 0
            for file_path in directory.rglob("*"):
                if file_path.is_file():
                    total_size += file_path.stat().st_size
            return total_size
        
        upload_size = get_dir_size(self.config.UPLOAD_DIR)
        reports_size = get_dir_size(self.config.REPORTS_DIR)
        total_size = upload_size + reports_size
        
        return {
            "upload_dir_size": upload_size,
            "upload_dir_size_mb": upload_size / 1024 / 1024,
            "reports_dir_size": reports_size,
            "reports_dir_size_mb": reports_size / 1024 / 1024,
            "total_size": total_size,
            "total_size_mb": total_size / 1024 / 1024,
            "upload_file_count": len(list(self.config.UPLOAD_DIR.glob("*"))),
            "report_file_count": len(list(self.config.REPORTS_DIR.glob("*")))
        }
    
    def backup_file(self, file_path: str, backup_dir: Optional[str] = None) -> str:
        """
        备份文件
        
        Args:
            file_path: 要备份的文件路径
            backup_dir: 备份目录（可选）
            
        Returns:
            备份文件路径
        """
        source_path = Path(file_path)
        
        if not source_path.exists():
            raise FileNotFoundError(f"源文件不存在: {file_path}")
        
        # 确定备份目录
        if backup_dir:
            backup_path = Path(backup_dir)
        else:
            backup_path = self.config.PROJECT_ROOT / "backups"
        
        backup_path.mkdir(exist_ok=True)
        
        # 生成备份文件名
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        backup_filename = f"{source_path.stem}_backup_{timestamp}{source_path.suffix}"
        backup_file_path = backup_path / backup_filename
        
        # 复制文件
        shutil.copy2(source_path, backup_file_path)
        
        return str(backup_file_path)
    
    def is_file_supported(self, filename: str) -> bool:
        """
        检查文件是否支持
        
        Args:
            filename: 文件名
            
        Returns:
            是否支持
        """
        extension = Path(filename).suffix.lower()
        return extension in self.config.ALLOWED_EXTENSIONS
    
    def get_file_type_info(self, filename: str) -> Dict[str, str]:
        """
        获取文件类型信息
        
        Args:
            filename: 文件名
            
        Returns:
            文件类型信息
        """
        extension = Path(filename).suffix.lower()
        
        type_mapping = {
            '.pdf': {'type': 'PDF文档', 'icon': '📄', 'description': 'Adobe PDF文档'},
            '.docx': {'type': 'Word文档', 'icon': '📝', 'description': 'Microsoft Word文档'},
            '.doc': {'type': 'Word文档', 'icon': '📝', 'description': 'Microsoft Word文档(旧版)'},
            '.txt': {'type': '文本文件', 'icon': '📋', 'description': '纯文本文件'}
        }
        
        return type_mapping.get(extension, {
            'type': '未知类型',
            'icon': '❓',
            'description': '未知文件类型'
        })
